package com.liuyi.tools.kits;

import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.EnumUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.experimental.Accessors;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 枚举工具类
 * </p>
 *
 * @author Mr.Fmy
 * @since 2020-10-23
 */
public class EnumsKits {

    private static final Map<Class, Map<String, Wrapper>> classWrapper = new HashMap<>();

    /**
     * 转换枚举字符串、
     * 例如
     * {key:1} 转换后 {key:one,keyCn:"第一"}
     *
     * @param dict     数据源
     * @param wrappers 转换值
     */
    @SuppressWarnings("unchecked")
    @Deprecated
    public static void wraEnumNames(Dict dict, Wrapper... wrappers) {
        for (Wrapper wrapper : wrappers) {
            String key = wrapper.getKey();
            if (dict.containsKey(key)) {
                Enum anEnum = EnumUtil.likeValueOf(wrapper.getAClass(), dict.get(key));

                if (anEnum != null) {
                    dict.put(key, anEnum.name());
                    if (anEnum instanceof IWEnum) {
                        dict.put(key + "Cn", ((IWEnum) anEnum).getD());
                    }
                }
            }
        }
    }

    /**
     * 转换枚举字符串、
     * 例如
     * {key:1} 转换后 {key:one,keyCn:"第一"}
     *
     * @param dict     数据源
     * @param wrappers 转换值
     */
    @SuppressWarnings("unchecked")
    public static void wraEnumNames(Dict dict, Map<String, Wrapper> wrappers) {
        wrappers.forEach((key, wrapper) -> {
            if (dict.containsKey(key)) {
                Enum anEnum = EnumUtil.likeValueOf(wrapper.getAClass(), dict.get(key));
                if (anEnum != null) {
                    dict.put(key, anEnum.name());
                    if (anEnum instanceof IWEnum) {
                        dict.put(key + "Cn", ((IWEnum) anEnum).getD());
                    }
                }
            }
        });
    }

    /**
     * 转换枚举value值为name
     * <p>
     * {name:0} 映射后 {name:OK}
     * </p>
     *
     * @param map      数据源，一般是map类型
     * @param pre      数据源key值前辍、可以不存在，存在的话列入 a.name 那么 a.为前辍
     * @param wrappers 转换值映射
     */
    @SuppressWarnings("unchecked")
    public static <T extends Map> void wraEnumValue(T map, String pre, Map<String, Wrapper> wrappers) {
        wrappers.forEach((k, wrapper) -> {
            String key = pre + k;
            Object v = map.get(key);
            Enum anEnum = EnumUtil.likeValueOf(wrapper.getAClass(), v);
            if (anEnum != null) {
                if (anEnum instanceof IWEnum) {
                    map.put(key, ((IWEnum) anEnum).getV());
                }
            }
        });
    }

    /**
     * 转换枚举name值为value 只转换一个
     *
     * @param key     key值
     * @param value   value值
     * @param pre     前辍
     * @param wrapper 转换映射
     */
    @SuppressWarnings("unchecked")
    public static Object wraEnumValue(String key, Object value, String pre, Wrapper wrapper) {
        if (wrapper == null) {
            return value;
        }
        String keyWra = pre + wrapper.getKey();
        if (key.equals(keyWra)) {
            Enum anEnum = EnumUtil.likeValueOf(wrapper.getAClass(), value);
            if (anEnum != null) {
                if (anEnum instanceof IWEnum) {
                    return ((IWEnum) anEnum).getV();
                }
            }
        }
        return value;
    }

    /**
     * 转换枚举值为枚举名，根据实体类转换
     */
    public static Object wraEnumValue(String key, Object value, String pre, Class... cs) {
        for (Class c : cs) {
            Map<String, Wrapper> wrappers = getClassWrapper(c);
            if (wrappers != null) {
                return wraEnumValue(key, value, pre, wrappers.get(key.replace(pre, "")));
            }
        }
        return value;
    }

    /**
     * 转换枚举值为枚举名，根据实体类转换
     */
    public static <T extends Map> void wraEnumValue(T map, String pre, Class... cs) {
        for (Class c : cs) {
            Map<String, Wrapper> wrappers = getClassWrapper(c);
            if (wrappers != null) {
                wraEnumValue(map, pre, wrappers);
            }
        }
    }

    /**
     * 转换枚举，根据实体类转换
     */
    public static void wraEnumNames(Dict dict, Class... cs) {
        for (Class c : cs) {
            Map<String, Wrapper> wrappers = getClassWrapper(c);
            if (wrappers != null) {
                wraEnumNames(dict, wrappers);
            }
        }
    }

    public static Map<String, Wrapper> getClassWrapper(Class c) {
        Map<String, Wrapper> wrappers;
        if (classWrapper.containsKey(c)) {
            wrappers = classWrapper.get(c);
        } else {
            //解析实体
            wrappers = classWrappers(c);
            classWrapper.put(c, wrappers);
        }
        return wrappers;
    }

    @SuppressWarnings("unchecked")
    public static Map<String, Wrapper> classWrappers(Class c) {
        Map<String, Wrapper> wrappers = new HashMap<>();
        Field[] declaredFields = ClassUtil.getDeclaredFields(c);
        for (Field field : declaredFields) {
            if (IWEnum.class.isAssignableFrom(field.getType()) && field.getType().isEnum()) {
                wrappers.put(field.getName(), new Wrapper(field.getName(), (Class<? extends Enum>) field.getType()));
            }
        }
        return wrappers.isEmpty() ? null : wrappers;
    }

    public interface IWEnum<T> {

        T getV();

        String getD();
    }

    @Data
    @Accessors(chain = true)
    @AllArgsConstructor
    public static class Wrapper {
        /**
         * K 值
         */
        private String key;
        /**
         * 对应的枚举
         */
        private Class<? extends Enum> aClass;
    }
}
